package db

import (
	"errors"
	"strings"

	"gddgame.cc/galaxy/common/dsl/web"
	"gddgame.cc/galaxy/utils/orm"
)

const (
	DefaultApp = "default"
)

// 替换基本的webController
type TableHandle struct {
	Controller web.Ctl
	Params     []web.Param
}

type Table struct {
	*orm.Model
	// 排序存储字段
	Sort string
	// 绑定存储字段
	Link string
	// 被绑定存储字段
	Linked string

	Format    func(data map[string]interface{})
	CanAdd    func(data map[string]interface{}) error
	CanEdit   func(id string, data map[string]interface{}) error
	CanDelete func(id string) error
	List      *TableHandle
	Add       *TableHandle
	Get       *TableHandle
	Delete    *TableHandle
	Edit      *TableHandle
}

var (
	appMap  = map[string]map[string]*Table{}
	tmpApp  = DefaultApp
	linkMap = map[string]*orm.Model{}
)

func SetGlobalApp(app string) {
	tmpApp = app
}

func RecoverGlobalApp() {
	tmpApp = DefaultApp
}

func AddTable(table *Table) {
	AddTableTo(table, tmpApp)
}

func AddTableTo(table *Table, app string) {
	var ok bool
	tableMap, ok := appMap[app]
	if !ok {
		tableMap = map[string]*Table{}
		appMap[app] = tableMap
	}
	tableName := table.TableName()
	_, ok = tableMap[tableName]
	if ok {
		panic(errors.New(tableName + " is exist"))
	}
	tableMap[tableName] = table
}

func FindTable(tableName string) (*Table, error) {
	return FindTableFrom(tableName, tmpApp)
}

func FindTableFrom(tableName string, app string) (*Table, error) {
	var ok bool
	tableMap, ok := appMap[app]
	if !ok {
		panic(errors.New(app + " is not exist"))
	}
	table, ok := tableMap[tableName]
	if !ok {
		fullTableName := FullTableName(tableName, app)
		table, ok = tableMap[fullTableName]
		if !ok {
			tableMap, ok = appMap[DefaultApp]
			if !ok {
				panic(errors.New(app + " is not exist"))
			}
			table, ok = tableMap[tableName]
			if !ok {
				return nil, errors.New(tableName + " is not exist")
			}
		}
	}
	return table, nil
}

//todo 判断表名是否有大写
func ShortTableName(tableName string, app string) string {
	return strings.Replace(tableName, app+"_", "", 1)
}

func FullTableName(tableName string, app string) string {
	return app + "_" + tableName
}

func BindExecutor(executor orm.Executor) {
	BindExecutorTo(executor, tmpApp)
}

func BindExecutorTo(executor orm.Executor, app string) {
	var ok bool
	tableMap, ok := appMap[app]
	if !ok {
		panic(errors.New(app + " is not exist"))
	}
	for _, table := range tableMap {
		table.Executor(executor)
	}
}

func InitLink(linkTable string) error {
	return InitLinkFrom(linkTable, tmpApp)
}

func InitLinkFrom(linkTable string, app string) error {
	model := orm.NewModel(linkTable, &Link{}, nil)
	if _, ok := linkMap[app]; ok {
		return errors.New(app + " link finish init")
	}
	linkMap[app] = model
	return nil
}

func GetLink(app string) (*orm.Model, error) {
	model, ok := linkMap[app]
	if !ok {
		return nil, errors.New(app + " link not init")
	}
	return model, nil
}
